package reader;

import model.solomon.Job;
import model.solomon.Problem;
import util.DistanceUtil;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

import org.apache.commons.io.IOUtils;

public class SolomonReader {

    public static final int VEHICLE_DATA_LINE_NUMBER = 4;
    public static final int JOB_DATA_BEGIN_LINE_NUMBER = 9;


    public static Problem parseProblem(String fileName) throws IOException {
        List<String> problemData = IOUtils.readLines(
                Objects.requireNonNull(SolomonReader.class.getClassLoader().getResourceAsStream(fileName)),
                StandardCharsets.UTF_8
        );
        return doParseProblem(problemData);
    }

    private static Problem doParseProblem(List<String> problemData) {
        Problem problem = new Problem();
        String[] vehicleData = split(problemData.get(VEHICLE_DATA_LINE_NUMBER));
        problem.vehicleNumber = Integer.parseInt(vehicleData[0]);
        problem.vehicleCapacity = Double.parseDouble(vehicleData[1]);
        for (String line : problemData.subList(JOB_DATA_BEGIN_LINE_NUMBER, problemData.size())) {
            Job job = parseJob(line);
            if (!Objects.isNull(job)) {
                problem.jobList.add(job);
            }
        }
        problem.distanceMatrix = calDistanceMatrix(problem.jobList);

        return problem;
    }

    private static Job parseJob(String line) {
        String[] dataArray = split(line);
        if (dataArray[0].isEmpty()) {
            return null;
        }

        int locationId = Integer.parseInt(dataArray[0]);
        double x = Double.parseDouble(dataArray[1]);
        double y = Double.parseDouble(dataArray[2]);

        double demand = Double.parseDouble(dataArray[3]);
        double startTime = Double.parseDouble(dataArray[4]);
        double endTime = Double.parseDouble(dataArray[5]);
        double serviceTime = Double.parseDouble(dataArray[6]);

        Job job = new Job();
        job.locationId = locationId;
        job.x = x;
        job.y = y;
        job.demand = demand;
        job.startTime = startTime;
        job.endTime = endTime;
        job.serviceTime = serviceTime;

        return job;
    }

    private static String[] split(String line) {
        return line.replace("\r", "").trim().split("\\s+");
    }

    private static double[][] calDistanceMatrix(List<Job> jobList) {
        double[][] distanceMatrix = new double[jobList.size()][jobList.size()];

        for (int i = 0; i < jobList.size(); i++) {
            for (int j = 0; j < jobList.size(); j++) {
                double[] from = {jobList.get(i).x, jobList.get(i).y};
                double[] to = {jobList.get(j).x, jobList.get(j).y};
                double distance = DistanceUtil.calculateEuc2D(from[0], from[1], to[0], to[1]);
                distanceMatrix[i][j] = distance;
            }
        }

        return distanceMatrix;
    }


}
